/*
 * GrepSearchUI.java
 *
 * Created on 17 November 2006, 14:47
 */

package com.filesearcher;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JComponent;

import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.BevelBorder;
import javax.swing.border.SoftBevelBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.jdesktop.layout.GroupLayout;
import org.jdesktop.layout.LayoutStyle;


/**
* This code was edited or generated using CloudGarden's Jigloo
* SWT/Swing GUI Builder, which is free for non-commercial
* use. If Jigloo is being used commercially (ie, by a corporation,
* company or business for any purpose whatever) then you
* should purchase a license for each developer using Jigloo.
* Please visit www.cloudgarden.com for details.
* Use of Jigloo implies acceptance of these licensing terms.
* A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR
* THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED
* LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE.
*/
/**
 *
 * @author  James
 */
public class GrepSearchUI extends javax.swing.JFrame {
    
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	public static final String VERSION_NUMBER = "0.10 BETA";
	public static final String RELEASE_DATE    = "not yet released";
	
	private static Map tabDataFiles = new HashMap();
	private static Map tabIndexes = new HashMap();
	//private static ArrayList tabDataFiles = new ArrayList(20);
	private static int previousSelectedTab = 0;
	private static boolean tabRemove = false;
	private static boolean firstSearch = true;
	
	private static ArrayList currentSearchThreads = new ArrayList();
	
	private File searchFile = null;
    private File fileName = null;
    private File saveFileName = null;
    //private int grepType = RunCommand.GREP_DEFAULT;    
    
    /** Creates new form GrepSearchUI */
    public GrepSearchUI() {
        try {
            
            String lnfName = UIManager.getSystemLookAndFeelClassName(); 
            // Set System L&F 
            UIManager.setLookAndFeel(lnfName);
            SwingUtilities.updateComponentTreeUI(this);
            this.pack();
            } 
            catch (UnsupportedLookAndFeelException e) {
                // handle exception
            }
            catch (ClassNotFoundException e) {
                // handle exception
            }
            catch (InstantiationException e) {
                // handle exception
            }
            catch (IllegalAccessException e) {
               // handle exception
            }
        
        initComponents();
        startRefreshFreeMemory();
        addDefaultTab();

        tabPane.setDoubleBuffered( true );
        
        tabPane.addChangeListener(new ChangeListener() {
        	// This method is called whenever the selected tab changes
        	public synchronized void stateChanged(ChangeEvent evt) 
        	{
        		JTabbedPane pane = ( JTabbedPane )evt.getSource();

        		if ( !tabRemove )
        		{
        			if ( previousSelectedTab != -1 )
        			{
        				ResultsTab previousSelectedTab = ( ResultsTab )pane.getComponentAt(GrepSearchUI.previousSelectedTab);        		

        				if ( previousSelectedTab.getSearchInProgress() )
        				{
        					System.out.println(" There is currently a search in progess on tab " + GrepSearchUI.previousSelectedTab );
        				}
        				else
        				{
//        					try 
//        					{
        						/* Compress the previous tab text and write it to a tmp file */
        						//byte[] data = StringCompress.compress( previousSelectedTab.getText() );
        						//writeTextToDisk(data,  previousSelectedTab);

        						/* Clear the text from the previous tab */
        						writeTextToDisk( previousSelectedTab.getText(), Integer.toString( previousSelectedTab.hashCode() ) );
        						previousSelectedTab.clearText();
        					} 
//        					catch (IOException e) 
//        					{
//        						// TODO Auto-generated catch block
//        						e.printStackTrace();
//        					}            	
//        				}
        			}
        		}
        		else
        		{
        			tabRemove = false;
        			//tabDataFiles.remove( previousSelectedTab );
        		}

        		/* Some garbage collection */
        		Runtime.getRuntime().gc();

        		/* Set the previous tab to be this current tab, because next time the above code runs, the current selected tab at THIS
        		 * point will infact be the previous tab! */
        		GrepSearchUI.previousSelectedTab = pane.getSelectedIndex();

        		int selectedIndex = pane.getSelectedIndex();

        		if ( selectedIndex != -1 )
        		{
        			ResultsTab currentTab = ( ResultsTab )pane.getComponentAt(selectedIndex);
        			message.setText( currentTab.getCurrentMessageText() );
        			message.setForeground( currentTab.getMessageColor() );        		

        			showLineNumbers.setSelected( currentTab.showLineNumbersSelected );
        			ignoreCase.setSelected( currentTab.ignoreCaseSelected );
        			exculdeContaining.setSelected( currentTab.excludeWordsSelected );
        			/* Collect the stored tab data for the currently selected tab */
        			//byte[] data = tabData.getTabData(selectedIndex);

        			/* Try to decompress it, then set the current tabs text using the decompressed data */
//        			try 
//        			{	
        				String hashCodeStr = Integer.toString( currentTab.hashCode() );
        		    	File tmpFile = ( File )tabDataFiles.get( hashCodeStr );
        		    	
        				currentTab.readTabResultsFromDisk( tmpFile );
        				//byte[] data = readTextFromDisk( currentTab );

        				//if ( data != null )
        				//{
        					//String tabDataString = StringCompress.decompress(data);

        					//DecompressThread decompressThread = new DecompressThread( data, currentTab );
        					//decompressThread.start();
        					
        					//    					try
        					//    					{
        					//    						currentTab.setText( tabDataString );
        					//    					}
        					//    					catch( OutOfMemoryError oom )
        					//    					{
        					//    						String messageText = "OutOfMemoryError caught trying to display results. Too many results!";

        					//    						currentTab.clearText();
        					//    						currentTab.setCurrentMessageText( messageText );
        					//    						currentTab.setMessageColor( Color.RED );

        					//    						message.setText( messageText );
        					//    						message.setForeground( Color.RED );
        					//    					}
        				//}
//        			} 
//        			catch (IOException e1) 
//        			{
//        				// TODO Auto-generated catch block
//        				e1.printStackTrace();
//        			}        			
        		}

        		/* Some more garbage collection */
        		Runtime.getRuntime().gc();            
        	}
        });

        /* Set the message font */
        Font font = message.getFont();
        Font newFont = new Font(font.getName(), Font.BOLD, 11);
        message.setFont(newFont);        
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    private void initComponents() {
        showFileFrame = new javax.swing.JFrame();
        jScrollPane1 = new javax.swing.JScrollPane();
        fileTextDisplay = new javax.swing.JTextArea();
        jPanel1 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        searchText = new javax.swing.JTextField();
        searchText.setBorder(new SoftBevelBorder(BevelBorder.LOWERED, null, null, null, null));
        searchText.addFocusListener(new FocusAdapter() {
        	public void focusGained(FocusEvent evt) {
        		//System.out.println("searchText.focusGained, event="+evt);
        		jPanel1.getRootPane().setDefaultButton(buttonSearch);        		
        	}
        });
        buttonSelectFile = new javax.swing.JButton();
        jLabel2 = new javax.swing.JLabel();
        currentSearchFile = new javax.swing.JTextField();
        buttonSearch = new javax.swing.JButton();
        jPanel2 = new javax.swing.JPanel();
        GroupLayout jPanel2Layout = new GroupLayout((JComponent)jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        //tabPane = new javax.swing.JTabbedPane();
        tabPane = new JTabbedPane();
        buttonClear = new javax.swing.JButton();
        buttonClearAll = new javax.swing.JButton();
        {
        	buttonSaveResults = new javax.swing.JButton();
        	buttonSaveResults.setText("Save Results");
        	buttonSaveResults.setVisible( false );
        	buttonSaveResults.addActionListener(new java.awt.event.ActionListener() {
        		public void actionPerformed(java.awt.event.ActionEvent evt) {
        			buttonSaveResultsActionPerformed(evt);
        		}
        	});
        }
        {
        	buttonShowFile = new javax.swing.JButton();
        	buttonShowFile.setText("Show File");
        	buttonShowFile.setVisible(false);
        	buttonShowFile.addActionListener(new java.awt.event.ActionListener() {
        		public void actionPerformed(java.awt.event.ActionEvent evt) {
        			buttonShowFileActionPerformed(evt);
        		}
        	});
        }
        jPanel3 = new javax.swing.JPanel();
        message = new javax.swing.JLabel();
        jPanel4 = new javax.swing.JPanel();
        exculdeContaining = new javax.swing.JCheckBox();
        showLineNumbers = new javax.swing.JCheckBox();
        saveResults = new javax.swing.JCheckBox();
        menuBar = new javax.swing.JMenuBar();
        jMenu2 = new javax.swing.JMenu();
        exitMenuItem = new javax.swing.JMenuItem();
        jMenu1 = new javax.swing.JMenu();
        jMenuItem1 = new javax.swing.JMenuItem();

        showFileFrame.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        fileTextDisplay.setColumns(20);
        fileTextDisplay.setRows(5);
        jScrollPane1.setViewportView(fileTextDisplay);

        org.jdesktop.layout.GroupLayout showFileFrameLayout = new org.jdesktop.layout.GroupLayout(showFileFrame.getContentPane());
        showFileFrame.getContentPane().setLayout(showFileFrameLayout);
        showFileFrameLayout.setHorizontalGroup(
            showFileFrameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(0, 400, Short.MAX_VALUE)
            .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 774, Short.MAX_VALUE)
        );
        showFileFrameLayout.setVerticalGroup(
            showFileFrameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(0, 300, Short.MAX_VALUE)
            .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 537, Short.MAX_VALUE)
        );

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("FileSearcher " + VERSION_NUMBER);
        setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Search"));
        jLabel1.setText("Search String :");

        buttonSelectFile.setText("Select File");
        buttonSelectFile.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonSelectFileActionPerformed(evt);
            }
        });

        jLabel2.setText("Current file to search :");

        currentSearchFile.setText("None");
        currentSearchFile.setEditable(false);
        currentSearchFile.setBorder(new SoftBevelBorder(BevelBorder.LOWERED, null, null, null, null));

        buttonSearch.setEnabled( false );
        buttonSearch.setText("Search");
        buttonSearch.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonSearchActionPerformed(evt);
            }
        });

        org.jdesktop.layout.GroupLayout jPanel1Layout = new org.jdesktop.layout.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel1Layout.createSequentialGroup()
                .add(13, 13, 13)
                .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                    .add(jLabel1)
                    .add(jLabel2))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(searchText, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 468, Short.MAX_VALUE)
                    .add(currentSearchFile, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 468, Short.MAX_VALUE))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                    .add(buttonSearch, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 81, Short.MAX_VALUE)
                    .add(buttonSelectFile))
                .addContainerGap())
        );

        jPanel1Layout.linkSize(new java.awt.Component[] {buttonSearch, buttonSelectFile}, org.jdesktop.layout.GroupLayout.HORIZONTAL);

        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel1Layout.createSequentialGroup()
                .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(buttonSearch)
                    .add(searchText, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(jLabel1))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(buttonSelectFile)
                    .add(currentSearchFile, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(jLabel2))
                .addContainerGap())
        );

        jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Results"));
        tabPane.setTabLayoutPolicy(javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT);
        {
        	freeMemoryLabel = new JLabel();        	
        }
        {
        	memoryLabel = new JLabel();
        	memoryLabel.setText("Used Mem / Maximum Mem : ");
        }

        buttonClear.setText("Clear");
        buttonClear.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonClearActionPerformed(evt);
                
                /* Force garbage collection */
                Runtime.getRuntime().gc();
            }
        });

        buttonClearAll.setText("Clear All");
        jPanel2Layout.setVerticalGroup(jPanel2Layout.createSequentialGroup()
        	.add(tabPane, 0, 270, Short.MAX_VALUE)
        	.addPreferredGap(LayoutStyle.UNRELATED)
        	.add(jPanel2Layout.createParallelGroup()
        	    .add(GroupLayout.LEADING, jPanel2Layout.createParallelGroup(GroupLayout.BASELINE)
        	        .add(GroupLayout.BASELINE, freeMemoryLabel, GroupLayout.PREFERRED_SIZE, 17, GroupLayout.PREFERRED_SIZE)
        	        .add(GroupLayout.BASELINE, memoryLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE))
        	    .add(GroupLayout.LEADING, jPanel2Layout.createParallelGroup(GroupLayout.BASELINE)
        	        .add(GroupLayout.BASELINE, buttonClear, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
        	        .add(GroupLayout.BASELINE, buttonClearAll, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)))
        	.addPreferredGap(LayoutStyle.RELATED));
        jPanel2Layout.setHorizontalGroup(jPanel2Layout.createSequentialGroup()
        	.addContainerGap()
        	.add(jPanel2Layout.createParallelGroup()
        	    .add(GroupLayout.LEADING, jPanel2Layout.createSequentialGroup()
        	        .add(memoryLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
        	        .addPreferredGap(LayoutStyle.RELATED)
        	        .add(freeMemoryLabel, GroupLayout.PREFERRED_SIZE, 218, GroupLayout.PREFERRED_SIZE)
        	        .add(0, 169, Short.MAX_VALUE)
        	        .add(buttonClear, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
        	        .addPreferredGap(LayoutStyle.UNRELATED)
        	        .add(buttonClearAll, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE))
        	    .add(GroupLayout.LEADING, tabPane, 0, 647, Short.MAX_VALUE))
        	.addContainerGap());
        buttonClearAll.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonClearAllActionPerformed(evt);
            }
        });

        jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder("Messages"));
        message.setText("Select the file that you wan't to search");

        org.jdesktop.layout.GroupLayout jPanel3Layout = new org.jdesktop.layout.GroupLayout(jPanel3);
        jPanel3.setLayout(jPanel3Layout);
        {
        	lineResultsPanel = new JPanel();
        	GroupLayout lineResultsPanelLayout = new GroupLayout((JComponent)lineResultsPanel);
        	lineResultsPanel.setLayout(lineResultsPanelLayout);
        	lineResultsPanel.setBorder(BorderFactory.createTitledBorder("Max Results"));
        	{
        		SpinnerNumberModel spinnerM = new SpinnerNumberModel( 10000, 1, 200000, 1 );
        		numOfLines = new JSpinner( spinnerM );
        		//numOfLines.setEditor( new JSpinner.NumberEditor( numOfLines, "000000"));
        		numOfLines.getEditor().setPreferredSize(new java.awt.Dimension(65, 11));
        		numOfLines.setSize(89, 22);
        	}
        	{
        		maxResultsLabel = new JLabel();
        		maxResultsLabel.setText("Line(s)");
        	}
        lineResultsPanelLayout.setHorizontalGroup(lineResultsPanelLayout.createSequentialGroup()
        		.addContainerGap()
        		.add(numOfLines, 0, 89, Short.MAX_VALUE)
        		.addPreferredGap(LayoutStyle.UNRELATED)
        		.add(maxResultsLabel, GroupLayout.PREFERRED_SIZE, 34, GroupLayout.PREFERRED_SIZE));
        lineResultsPanelLayout.setVerticalGroup(lineResultsPanelLayout.createSequentialGroup()
        		.add(lineResultsPanelLayout.createParallelGroup(GroupLayout.BASELINE)
        		    .add(GroupLayout.BASELINE, numOfLines, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
        		    .add(GroupLayout.BASELINE, maxResultsLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE))
        		.addPreferredGap(LayoutStyle.RELATED));
        }
        jPanel3Layout.setHorizontalGroup(
            jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel3Layout.createSequentialGroup()
                .addContainerGap()
                .add(message)
                .addContainerGap(662, Short.MAX_VALUE))
        );
        jPanel3Layout.setVerticalGroup(
            jPanel3Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(message)
        );

        jPanel4.setBorder(javax.swing.BorderFactory.createTitledBorder("Search Options"));
        exculdeContaining.setText("Exclude Containing");
        exculdeContaining.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
        exculdeContaining.setMargin(new java.awt.Insets(0, 0, 0, 0));

        showLineNumbers.setText("Show Line Numbers");
        showLineNumbers.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
        showLineNumbers.setMargin(new java.awt.Insets(0, 0, 0, 0));
        {
        	ignoreCase = new JCheckBox();
        	ignoreCase.setText("Ignore Case");
        	ignoreCase.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
        }
        showLineNumbers.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                showLineNumbersActionPerformed(evt);
            }
        });

        saveResults.setText("Save Results");
        saveResults.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
        saveResults.setMargin(new java.awt.Insets(0, 0, 0, 0));
        saveResults.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveResultsActionPerformed(evt);
            }
        });

        org.jdesktop.layout.GroupLayout jPanel4Layout = new org.jdesktop.layout.GroupLayout(jPanel4);
        jPanel4.setLayout(jPanel4Layout);
        jPanel4Layout.setVerticalGroup(jPanel4Layout.createSequentialGroup()
        	.add(showLineNumbers, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
        	.addPreferredGap(LayoutStyle.RELATED)
        	.add(exculdeContaining, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
        	.addPreferredGap(LayoutStyle.RELATED)
        	.add(saveResults, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
        	.addPreferredGap(LayoutStyle.RELATED)
        	.add(ignoreCase, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
        	.addContainerGap(31, 31));
        jPanel4Layout.setHorizontalGroup(jPanel4Layout.createParallelGroup()
        	.add(GroupLayout.LEADING, jPanel4Layout.createSequentialGroup()
        	    .add(ignoreCase, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        	    .addContainerGap(14, 14))
        	.add(jPanel4Layout.createSequentialGroup()
        	    .add(jPanel4Layout.createParallelGroup()
        	        .add(GroupLayout.LEADING, exculdeContaining, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
        	        .add(GroupLayout.LEADING, jPanel4Layout.createSequentialGroup()
        	            .add(saveResults, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
        	            .add(32))
        	        .add(GroupLayout.LEADING, showLineNumbers, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE))
        	    .addContainerGap(34, 34)));

        jMenu2.setText("File");
        exitMenuItem.setText("Exit");
        exitMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                exitMenuItemActionPerformed(evt);
            }
        });

        jMenu2.add(exitMenuItem);

        menuBar.add(jMenu2);

        jMenu1.setText("Help");
        jMenuItem1.setText("About");
        jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                aboutMenuItemActionPerformed();
            }
        });
        
        jMenu1.add(jMenuItem1);

        menuBar.add(jMenu1);

        setJMenuBar(menuBar);

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setVerticalGroup(layout.createSequentialGroup()
        	.addContainerGap()
        	.add(layout.createParallelGroup()
        	    .add(GroupLayout.LEADING, jPanel1, GroupLayout.PREFERRED_SIZE, 107, GroupLayout.PREFERRED_SIZE)
        	    .add(GroupLayout.LEADING, jPanel4, GroupLayout.PREFERRED_SIZE, 107, GroupLayout.PREFERRED_SIZE))
        	.addPreferredGap(LayoutStyle.RELATED)
        	.add(layout.createParallelGroup()
        	    .add(GroupLayout.LEADING, jPanel3, GroupLayout.PREFERRED_SIZE, 56, GroupLayout.PREFERRED_SIZE)
        	    .add(GroupLayout.LEADING, lineResultsPanel, GroupLayout.PREFERRED_SIZE, 56, GroupLayout.PREFERRED_SIZE))
        	.addPreferredGap(LayoutStyle.RELATED)
        	.add(jPanel2, 0, 342, Short.MAX_VALUE)
        	.addContainerGap());
        layout.setHorizontalGroup(layout.createSequentialGroup()
        	.addContainerGap()
        	.add(layout.createParallelGroup()
        	    .add(layout.createSequentialGroup()
        	        .add(layout.createParallelGroup()
        	            .add(layout.createSequentialGroup()
        	                .add(0, 0, GroupLayout.PREFERRED_SIZE)
        	                .add(jPanel3, 0, 518, Short.MAX_VALUE))
        	            .add(GroupLayout.LEADING, jPanel1, 0, 518, Short.MAX_VALUE))
        	        .addPreferredGap(LayoutStyle.RELATED)
        	        .add(layout.createParallelGroup()
        	            .add(GroupLayout.LEADING, lineResultsPanel, GroupLayout.PREFERRED_SIZE, 161, GroupLayout.PREFERRED_SIZE)
        	            .add(GroupLayout.LEADING, jPanel4, GroupLayout.PREFERRED_SIZE, 161, GroupLayout.PREFERRED_SIZE)))
        	    .add(GroupLayout.LEADING, jPanel2, 0, 685, Short.MAX_VALUE))
        	.addContainerGap());
        pack();
        this.setSize(713, 608);
    }

    private void buttonSaveResultsActionPerformed(java.awt.event.ActionEvent evt) 
    {
              
    }

    private void saveResultsActionPerformed(java.awt.event.ActionEvent evt) 
    {
        if ( saveResults.isSelected() == true ) {
            
            //... Open a file dialog.

            JFileChooser fileChooser = new JFileChooser();
            File saveName;
            
            if ( searchText.getText().equalsIgnoreCase(""))
            {
            	saveName = new File("fileSearch_results.txt");
            }
            else
            {
            	saveName = new File("fileSeacher_results_" + searchText.getText() + ".txt");
            }
            
            fileChooser.setSelectedFile(saveName);
            fileChooser.setApproveButtonText("Save");
            fileChooser.setDialogTitle("Choose location to save the search results");

            int retval = fileChooser.showOpenDialog(GrepSearchUI.this);

            if (retval == JFileChooser.APPROVE_OPTION) {
                //... The user selected a file, get it, use it.
                fileName = fileChooser.getSelectedFile();
                
                int response = checkFileExistance(fileName);
                
                if (response == JOptionPane.CANCEL_OPTION) {
                    
                    saveFileName = null;
                    JOptionPane.showMessageDialog(this, "You did not enter a vaild save file name, so your results will NOT be saved.");
                    saveResults.setSelected(false);
                    
                } else {
                
                    if ( fileName.toString().endsWith(".txt") ) {
                        saveFileName = fileName;
                    }else{
                        saveFileName = new File(fileName + ".txt");
                    }
                
                }
            }            
        }       
    }

    private void buttonShowFileActionPerformed(java.awt.event.ActionEvent evt) 
    {
        if ( searchFile == null ) 
        {
            message.setForeground(Color.RED);
            message.setText("You need to select a file before trying to view it.");
        }
        else
        {
            readFile();
            showFileFrame.setTitle(searchFile.toString());
            showFileFrame.pack();
            showFileFrame.setVisible(true);
            message.setForeground(Color.BLACK);
            message.setText("File : "+searchFile+ " has been displayed in a new window");
        }
    }

    private void buttonClearAllActionPerformed(java.awt.event.ActionEvent evt) 
    {
    	/*
    	 * Lets terminate any threads that are currently runing. This means that
    	 * tabs will not attempt to have there results set or anything similar, 
    	 * after they have been removed
    	 */
    	Iterator i = currentSearchThreads.iterator();
    	
    	while ( i.hasNext() )
    	{
    		SearchThread sThread = ( SearchThread )i.next();
    		
    		if ( sThread != null && sThread.isAlive() )
    		{
    			sThread.stop();
    		}
    	}
    	
    	tabPane.removeAll();
        addDefaultTab();
        
        message.setText("");
        showLineNumbers.setSelected( false );
        saveResults.setSelected( false );
        exculdeContaining.setSelected( false );
        
        numOfLines.setValue(new Integer(10000));
        
        searchText.setText("");
        
        tabDataFiles.clear();
    }
    
    private void showLineNumbersActionPerformed(java.awt.event.ActionEvent evt) 
    {
    	// TODO add your handling code here:
    }

    private void buttonSelectFileActionPerformed(java.awt.event.ActionEvent evt) 
    {
    	JFileChooser fileChooser = null;
    	File file = new File("");
    	boolean exitFileChooser = false;

    	while ( !file.exists() && exitFileChooser != true )
    	{
    		//... Open a file dialog.         
    		if ( fileChooser == null )
    		{
    			fileChooser = new JFileChooser();	
    		}
    		
    		int retval = fileChooser.showOpenDialog(GrepSearchUI.this);

    		if ( retval == JFileChooser.APPROVE_OPTION ) 
    		{
    			//... The user selected a file, get it, use it.
    			file = fileChooser.getSelectedFile();

    			if ( file.exists() )
    			{
    				currentSearchFile.setText(file.toString());
    				searchFile = fileChooser.getSelectedFile();

    				if ( searchText.getText().equalsIgnoreCase(""))
    				{
    					message.setText("Now enter a search string to search the file for");
    				}
    			}
    			else
    			{
    				JOptionPane.showMessageDialog( this, "File " + file.getName() + " doesn't exist, please select a valid file");
    			}
    		}
    		else if ( retval == JFileChooser.CANCEL_OPTION )
    		{
    			exitFileChooser = true;
    		}
    	}
    	
    	buttonSearch.setEnabled( true );
    }
             

    private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitMenuItemActionPerformed
        System.exit(1);
    }//GEN-LAST:event_exitMenuItemActionPerformed
    
    private void aboutMenuItemActionPerformed()
    {
    	AboutDialog about = new AboutDialog(this);
    	about.setVisible(true);
    }

    private void buttonClearActionPerformed(java.awt.event.ActionEvent evt) 
    {
    	if ( tabPane.getTabCount() > 0 )
    	{
    		/* Set tab remove true so that the tab pane listener knows we are removing a tab */
    		tabRemove = true;

    		ResultsTab comp = ( ResultsTab )tabPane.getComponentAt( tabPane.getSelectedIndex() );
    		String hashCodeStr = Integer.toString( comp.hashCode() );
    		
    		tabDataFiles.remove( hashCodeStr );
    		
    		//terminate any search that is currently in progress
    		comp.terminateSearchThread();
    		comp.clearText();
    		tabPane.remove( comp );    		

    		if ( tabPane.getTabCount() == 0) 
    		{
    			addDefaultTab();
    		}
    		else
    		{
    			tabPane.setSelectedIndex( 0 );
    		}

    		message.setText("Tab removed sucessfully");
    		message.setForeground(Color.BLACK);
    		
    		int tabCount = tabPane.getTabCount();
    		
    		if ( tabCount > 0 )
    		{
    			for (int i=0; i<tabCount; i++)
    			{
    				ResultsTab tab = ( ResultsTab )tabPane.getComponentAt( i );
    				
    				System.out.println("Tab " + tab.getTabIndexNumber() + "'s index number is being changed to " + i );
    				
    				tab.setTabIndexNumber( i );
    			}
    		}
    		
    		
    	}
    	
    	Runtime.getRuntime().gc();
    }
    
    public void addNewTab(ResultsTab tab)
    {
    	String tmpName;
    	String tabName;
        
        if ( exculdeContaining.isSelected() )
        	tmpName = "Exclude: " + tab.getSearchText();
        else
        	tmpName = "Search: " + tab.getSearchText();
        
        if ( tmpName.length() > 15 )
        {
        	tabName = tmpName.substring(0, 12);
        	tabName += "...";  
        	tab.setTabTitle( tabName );
        }
        else
        {
        	tabName = tmpName;
        	tab.setTabTitle( tabName );
        }
        
		if ( tabPane.getTabCount() > 0 )
			tab.clearText();
		
		tabPane.addTab( tab.getTabTitle(), tab);
		
		tab.setTabIndexNumber( tabPane.getTabCount() - 1 );
		tabPane.setToolTipTextAt( tab.getTabIndexNumber() , tmpName );
		
		tabIndexes.put( Integer.toString( tab.hashCode() ), Integer.toString( tab.getTabIndexNumber() ) );
    }
    
    public void setTabTitle( ResultsTab tab )
    {
    	String title = tab.getTabTitle();
    	
    	tabPane.setTitleAt( tab.getTabIndexNumber(), title);
    }

    private void buttonSearchActionPerformed(java.awt.event.ActionEvent evt) 
    {
    	/* Store the search text in a variable, and then clear the search box */
     	String searchString = searchText.getText().trim();
     	searchText.setText("");
    	
    	Runtime.getRuntime().gc();
    	
        if ( searchFile == null ) 
        {
            message.setForeground(Color.RED);
            message.setText("Please select a file before trying to search");
        }
        else if ( searchString.length() == 0 ) 
        {
            message.setForeground(Color.RED);
            message.setText("You need to enter a string to search for. Theres no point searching a file for nothing!");
        }
        else
        {
        	/* TODO make sure they all work, because currently some dont!?!? */
        	boolean lineNumbers = showLineNumbers.isSelected();
            boolean save = saveResults.isSelected();
            boolean exclude = exculdeContaining.isSelected();
            boolean ignore = ignoreCase.isSelected();
            File saveFile = saveFileName;
            
            SpinnerNumberModel model = (SpinnerNumberModel)numOfLines.getModel();
            int maxLines = model.getNumber().intValue();
            
            if ( !searchFile.exists() ) 
            {
            	message.setText("File " + searchFile + " does not exist!");
            	message.setForeground(Color.RED);
            }
            else if (!searchFile.canRead() )
            {
            	message.setText("Cant read file " + searchFile + " it might be locked by another process");
            	message.setForeground(Color.RED);
            }
            else
            {
            	SearchThread sThread = new SearchThread( searchString, searchFile, save, saveFile, exclude, maxLines, lineNumbers, ignore, this );
            	
            	//lets add this thread into the thread list
            	GrepSearchUI.addSearchThread( sThread );
            	
            	sThread.setPriority( Thread.MIN_PRIORITY );
            	sThread.start();
            	 /*            	
            	ResultsTab resultTab = sThread.getResultsTab();
            	message.setText( resultTab.getCurrentMessageText() );
            	this.addNewTab( resultTab );
            	tabPane.setSelectedIndex(tabPane.getTabCount() - 1);
            	*/
            	/*
            	StringBuffer results = new StringBuffer();
            	Grep myGrep = new Grep();
            	results = myGrep.searchFile(searchFile, searchText.getText());
            	
            	if ( Grep.numOfResults == Grep.maxResultLines )
            	{
            		String message = "Maximum number of lines reached. " +
					"There could be more results for your search, but you specifed not to " +
					"return more than " + Grep.maxResultLines + " lines. \r\n\nYou could increase the number of lines " +
					"returned, or try a more specific search that will produce less matching lines";
			
            		JOptionPane.showMessageDialog(this, message);
            	}

            	if ( results.length() == 0 ) 
                {
                    message.setText("There were no matching results for your search");
                    message.setForeground(Color.RED);
                }
                else
                {
                    ResultsTab newTab = new ResultsTab(searchText.getText());
                	
                    //message.setForeground(Color.BLACK);
                    message.setForeground(new Color(0, 100, 0));
                    message.setText("Results found: " + Grep.numOfResults + " matching lines ");
                                    
                    Runtime.getRuntime().gc();
                    
                    try
                    {
                     	newTab.setDoubleBuffered( true );
                    	newTab.setText( results.toString() );
                    	//newPane.setViewportView(searchResults);
                        
                        this.addNewTab(newTab);
                        tabPane.setSelectedIndex(tabPane.getTabCount() - 1);
                    }
                    catch ( OutOfMemoryError oom )
                    {
                    	String message = "OutOfMemory : Too many results returned.\r\r\n " +
                    			"Try reducing the maximum number of return lines, or create a more" +
                    			"specific search that will return less lines.";                    		
                    	JOptionPane.showMessageDialog(this, message);
                    	
                    	this.message.setForeground(Color.RED);
                    	this.message.setText("OutOfMemoryError caught, results can not be displayed!");                  
                    }
                                    
                    Runtime.getRuntime().gc();
                    
                    searchText.setText(null);
                }*/            	            
            }                                    
        }
        
    }//GEN-LAST:event_buttonSearchActionPerformed
    
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new GrepSearchUI().setVisible(true);
            }
        });
    }
    
    private void addDefaultTab() 
    {
    	//TODO need to add some kind of default welcome tab
    }

    private void readFile() {
        
        try {
            BufferedReader in = new BufferedReader(new FileReader(searchFile));
            String str;
            while ((str = in.readLine()) != null) {
                   appendShowFileText(str);
            }
            in.close();
        } catch (IOException e) {
        }
        
    }
    
    private void appendShowFileText(String text) {
        
        fileTextDisplay.append(text);
        //add a new line
        fileTextDisplay.append("\n");
        
    }
    
    public File openSaveFileDialog() {
        
        //... Open a file dialog.

        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setApproveButtonText("Save");
        fileChooser.setDialogTitle("Choose location to save the search results");

        int retval = fileChooser.showOpenDialog(GrepSearchUI.this);

        if (retval == JFileChooser.APPROVE_OPTION) {
            //... The user selected a file, get it, use it.
            fileName = fileChooser.getSelectedFile();
            
            if ( fileName.toString().endsWith(".txt") ) {
                saveFileName = fileName;
            }else{
                saveFileName = new File(fileName + ".txt");
            }
        }
        
        return saveFileName;
    }
    
    private int checkFileExistance(File fileName) {
        
        int overWrite = 0;
        
        if ( fileName.exists () ) {
            overWrite = JOptionPane.showConfirmDialog (null, "Overwrite existing file?",
                        "Confirm Overwrite",
                        JOptionPane.OK_CANCEL_OPTION,
                        JOptionPane.QUESTION_MESSAGE);
        }
        
        return overWrite;
        
    }
    
    public void writeTextToDisk( String results, String tabHashCode )
    {
    	File tmpFile;
		
    	try 
    	{
    		
			tmpFile = File.createTempFile( "fileSearcherTab-" + tabHashCode, ".tmp" );
			tmpFile.deleteOnExit();

			tabDataFiles.put( tabHashCode, tmpFile );
			/*
			try
			{
				tabDataFiles.get( tabNumber );
				tabDataFiles.set( tabNumber, tmpFile );
			}
			catch ( IndexOutOfBoundsException iob )
			{
				tabDataFiles.add( tabNumber, tmpFile );
			} */
		} 
    	catch (IOException e1) 
    	{
			// TODO Auto-generated catch block
			e1.printStackTrace();
			tmpFile = null;
		}
    	
    	String[] lines = results.split( "\n" );
		
    	if ( tmpFile != null && tmpFile.exists() )
    	{
    		//tab.writeTabResultsToDisk( tmpFile );
    		try 
    		{
    			FileWriter fileWriter = new FileWriter( tmpFile );
    			BufferedWriter out = new BufferedWriter( fileWriter );
    			
    			for ( int i=0; i < lines.length; i++ )
    			{
    				if ( i > 0 )
    						out.write( "\n" + lines[i] );
    					else
    						out.write( lines[i] );
    			}
    			
    			//out.write( results );
    			
    			out.close();
    		} 
    		catch (IOException e) 
    		{
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    }
    
    private byte[] readTextFromDisk(ResultsTab tab ) throws IOException
    {
    	String hashCodeStr = Integer.toString( tab.hashCode() );
    	File tmpFile = ( File )tabDataFiles.get( hashCodeStr );

    	if ( tmpFile != null )
    	{
    		InputStream is = null;

    		try 
    		{
    			is = new FileInputStream(tmpFile);
    		} catch (FileNotFoundException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}

    		// Get the size of the file
    		long length = tmpFile.length();

    		if (length > Integer.MAX_VALUE) {
    			// File is too large
    		}

    		// Create the byte array to hold the data
    		byte[] bytes = new byte[(int)length];

    		// Read in the bytes
    		int offset = 0;
    		int numRead = 0;
    		try {
    			while (offset < bytes.length
    					&& (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
    				offset += numRead;
    			}
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}

    		// Ensure all the bytes have been read in
    		if (offset < bytes.length) {
    			throw new IOException("Could not completely read file "+tmpFile.getName());
    		}

    		// Close the input stream and return bytes
    		is.close();   

    		return bytes;
    	}
    	else
    	{
    		return new byte[0];
    	}
    }
    
    public int getTabIndexNumber( ResultsTab tab )
    {
    	if ( tab != null )
    	{
    		return Integer.parseInt( (String)tabIndexes.get( Integer.toString( tab.hashCode() ) ) );
    	}
    	
		return -1;
    }
    
    public static File getTabTempFileName( ResultsTab tab )
    {
    	return ( File )tabDataFiles.get( Integer.toString( tab.hashCode() ) );    
    }
    
    public static Map getTabIndexes()
    {
    	return tabIndexes;
    }
    
    public static void addSearchThread( SearchThread thread )
    {
    	currentSearchThreads.add( thread );
    }
    
    public static void removeSearchThread( SearchThread thread )
    {
    	currentSearchThreads.remove( thread );
    }
    
    private void startRefreshFreeMemory()
    {
    	/*Thread refreshMemoryThread = new Thread() {
    		public void run()
    		{
    			while (true)
    			{
    				//long usedMem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
    				//String used = Long.toString( usedMem );
    				
    				String free =  Long.toString( Runtime.getRuntime().freeMemory() );
					String total = Long.toString( Runtime.getRuntime().totalMemory() );
					//String max = Long.toString( Runtime.getRuntime().maxMemory() );
					freeMemoryLabel.setText( free + " / " + total);
					
					if ( Runtime.getRuntime().freeMemory() < 100000 )
						freeMemoryLabel.setForeground( Color.RED );
					else
						freeMemoryLabel.setForeground( new Color( 0, 128, 0 ) );
					
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
    			}
    		}
    	};*/
    	
    	MemoryThread refreshMemoryThread = new MemoryThread();
    	refreshMemoryThread.start();
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton buttonClear;
    private javax.swing.JButton buttonClearAll;
    private JLabel maxResultsLabel;
    public JCheckBox ignoreCase;
    static JLabel freeMemoryLabel;
    private JLabel memoryLabel;
    private JSpinner numOfLines;
    private JPanel lineResultsPanel;
    private javax.swing.JButton buttonSaveResults;
    private javax.swing.JButton buttonSearch;
    private javax.swing.JButton buttonSelectFile;
    private javax.swing.JButton buttonShowFile;
    private javax.swing.JTextField currentSearchFile;
    private javax.swing.JMenuItem exitMenuItem;
    private javax.swing.JTextArea fileTextDisplay;
    public javax.swing.JCheckBox exculdeContaining;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenu jMenu2;
    private javax.swing.JMenuItem jMenuItem1;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JMenuBar menuBar;
    public javax.swing.JLabel message;
    private javax.swing.JCheckBox saveResults;
    private javax.swing.JTextField searchText;
    private javax.swing.JFrame showFileFrame;
    public javax.swing.JCheckBox showLineNumbers;
    //private javax.swing.JTabbedPane tabPane;
    public static JTabbedPane tabPane;
    // End of variables declaration//GEN-END:variables    
}
